#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>

#define NUM_PHILOSOPHER 5
#define NUM_TAKE 3

bool chopstick[NUM_PHILOSOPHER];
sem_t chopstick_lock[NUM_PHILOSOPHER];


void take_chopsticks(int number) {
    int chopstick_taked;
    while (true) {
        chopstick_taked = sem_trywait(&chopstick_lock[number]);
        if (chopstick_taked == 0) {
            chopstick_taked = sem_trywait(&chopstick_lock[(number + 1) % NUM_PHILOSOPHER]);
            if (chopstick_taked == 0) {
                chopstick[number] = false;
                chopstick[(number + 1) % NUM_PHILOSOPHER] = false;
                break;
            }
            else {
                sem_post(&chopstick_lock[number]);
            }
        }
    }
}

void put_chopsticks(int number) {
    chopstick[number] = true;
    chopstick[(number + 1) % NUM_PHILOSOPHER] = true;
    sem_post(&chopstick_lock[number]);
    sem_post(&chopstick_lock[(number + 1) % NUM_PHILOSOPHER]);
}

void *philosopher(void *arg) {
    int philosopher_id = *(int*)arg;
    for (int i = 0; i < NUM_TAKE; i++) {
        printf("philosopher %d is thinking\n", philosopher_id);
        sleep(1);
        take_chopsticks(philosopher_id);
        printf("philosopher %d is eating\n", philosopher_id);
        sleep(1);
        put_chopsticks(philosopher_id);
    }
    return NULL;
}

int main() {
    for (int i = 0; i < NUM_PHILOSOPHER; i++) {
        sem_init(&chopstick_lock[i], 0, 1);
    }
    memset(chopstick, 1, sizeof(bool) * NUM_PHILOSOPHER);
    int index[NUM_PHILOSOPHER];
    for (int i = 0; i < NUM_PHILOSOPHER; i++) {
        index[i] = i;
    }

    pthread_t tids[NUM_PHILOSOPHER];
    for (int i = 0; i < NUM_PHILOSOPHER; i++) {
        pthread_create(&tids[i], NULL, philosopher, (void*)&index[i]);
    }
    for (int i = 0; i < NUM_PHILOSOPHER; i++) {
        pthread_join(tids[i], NULL);
    }

    for (int i = 0; i < NUM_PHILOSOPHER; i++) {
        sem_destroy(&chopstick_lock[i]);
    }

    return 0;
}
